/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.cmd.identity;

import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.dao.EntityCallback;
import cn.easyplatform.dao.IdentityDao;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.OrgDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.dos.UserDo;
import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.beans.LogicBean;
import cn.easyplatform.i18n.I18N;
import cn.easyplatform.interceptor.AbstractCommand;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.lang.Times;
import cn.easyplatform.log.LogManager;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.response.LoginResponseMessage;
import cn.easyplatform.messages.response.SimpleResponseMessage;
import cn.easyplatform.messages.vos.AuthorizationVo;
import cn.easyplatform.messages.vos.OrgVo;
import cn.easyplatform.messages.vos.RoleVo;
import cn.easyplatform.services.ISubject;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.StateType;
import cn.easyplatform.util.IdentityUtils;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import static cn.easyplatform.type.UserType.TYPE_ADMIN;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class CallbackCmd extends AbstractCommand<SimpleRequestMessage> {

    /**
     * @param req
     */
    public CallbackCmd(SimpleRequestMessage req) {
        super(req);
    }

    @Override
    public IResponseMessage<?> execute(final CommandContext cc) {
        if (req.getBody() == null) {//发送验证码
            return doCallback(cc, cc.getProjectService().getConfig().getString("user.authentication.callback"), null);
        } else {
            IResponseMessage<?> rp = doCallback(cc, cc.getProjectService().getConfig().getString("user.authentication.callback"), (String) req.getBody());
            if (rp.isSuccess()) {
                UserDo userInfo = cc.getUser();
                userInfo.setLoginDate(new Date());
                userInfo.setLastAccessTime(new Date());
                int remainingDays = 0;
                Date now = Times.toDay();
                if (userInfo.getValidDays() > 0) {// 是否过期
                    int oneDay = 24 * 60 * 60 * 1000;
                    Date when = new Date(userInfo.getValidDate().getTime()
                            + userInfo.getValidDays() * oneDay);
                    int days = cc.getProjectService().getConfig().getDaysRemaining();
                    if (days > 0) {
                        remainingDays = (int) ((now.getTime() - when.getTime()) / oneDay);
                        if (remainingDays > days)// 如果剩余天数大于指定的天数，重置为零
                            remainingDays = 0;
                    }
                }
                IdentityDao dao = cc.getIdentityDao(false);
                EntityCallback<BaseEntity> cb = new EntityCallback<BaseEntity>() {
                    @Override
                    public BaseEntity getEntity(String entityId) {
                        return cc.getEntity(entityId);
                    }

                    public String getLabel(String code) {
                        return RuntimeUtils.getLabel(cc, code);
                    }
                };
                if (userInfo.getType() == TYPE_ADMIN) {// 管理用户不需要去找机构
                    userInfo.setOrg(new OrgDo());
                    userInfo.getOrg().setId("admin");
                    userInfo.getOrg().setName("admin");
                    userInfo.getOrg().setExtraInfo(new HashMap<>());
                    List<RoleVo> roles = dao.getUserRoles(cc.getUser().getId(), cc.getEnv()
                            .getDeviceType().getName(), cb);
                    userInfo.setRoles(roles);
                    LoginResponseMessage resp = new LoginResponseMessage(
                            new AuthorizationVo(null, roles));
                    resp.setType(userInfo.getType());
                    resp.setName(userInfo.getName());
                    if (remainingDays > 0)
                        resp.setTooltip(I18N.getLabel("app.user.expiring", remainingDays));
                    else if (cc.getProjectService().getConfig().getCheckPasswordPattern() != null) {
                        Matcher matcher = cc.getProjectService().getConfig().getCheckPasswordPattern().matcher(userInfo.getOriginalPassword());
                        if (!matcher.find())
                            resp.setTooltip(cc.getProjectService().getConfig().getCheckPasswordMessage());
                    }
                    userInfo.setState(StateType.START);
                    cc.setUser(userInfo);
                    cc.getSync().clear();
                    IdentityUtils.log(cc, dao);
                    LogManager.startUser(cc.getEngineConfiguration().getLogPath(), cc.getEnv().getId(), userInfo);
                    return resp;
                }
                List<OrgVo> orgs = dao.getUserOrgs(userInfo.getId(), cb);
                if (orgs.isEmpty()) {
                    cc.logout();
                    return MessageUtils.userNotOrg(userInfo.getId());
                }
                try {
                    LoginResponseMessage resp = null;
                    if (orgs.size() == 1) {// 默认的机构号
                        String orgId = orgs
                                .remove(0).getId();
                        AuthorizationVo av = IdentityUtils.getUserAuthorization(cc, userInfo, orgId);
                        resp = new LoginResponseMessage(av);
                        resp.setOrgId(orgId);
                        if (resp.isSuccess())
                            LogManager.startUser(cc.getEngineConfiguration().getLogPath(), cc.getEnv().getId(), userInfo);
                    } else {
                        // 由用户选择机构
                        resp = new LoginResponseMessage(orgs);
                    }
                    resp.setType(userInfo.getType());
                    resp.setName(userInfo.getName());
                    cc.setUser(userInfo);
                    if (remainingDays > 0)
                        resp.setTooltip(I18N.getLabel("app.user.expiring", remainingDays));
                    else if (cc.getProjectService().getConfig().getCheckPasswordPattern() != null) {
                        Matcher matcher = cc.getProjectService().getConfig().getCheckPasswordPattern().matcher(userInfo.getOriginalPassword());
                        if (!matcher.find())
                            resp.setTooltip(cc.getProjectService().getConfig().getCheckPasswordMessage());
                    }
                    IdentityUtils.log(cc, dao);
                    return resp;
                } catch (Exception ex) {
                    LogManager.stopUser(userInfo);
                    Subject currentUser = SecurityUtils.getSubject();
                    ((ISubject) currentUser).setAuthenticate(false);
                    return MessageUtils
                            .userAuthorizationError(userInfo.getId(), ex);
                }
            } else
                return rp;
        }
    }

    private IResponseMessage<?> doCallback(CommandContext cc, String cb, String checkCode) {
        LogicBean lb = cc.getProjectService().getEntityHandler().getEntity(cb);
        Map<String, Object> systemVariables = new HashMap<String, Object>();
        RuntimeUtils.initWorkflow(systemVariables, null);
        RecordContext rc = new RecordContext(new Record(), systemVariables, new HashMap<>());
        rc.setVariable(new FieldDo("type", FieldType.INT, checkCode == null ? 2 : 3));//设置类型
        if (checkCode != null)
            rc.setVariable(new FieldDo("checkCode", FieldType.VARCHAR, checkCode));//设置验证码
        String code = RuntimeUtils.eval(cc, lb, rc);//发送验证码
        if (!"0000".equals(code))
            return new SimpleResponseMessage(code, cc.getMessage(
                    code, rc));
        return new SimpleResponseMessage();
    }

    @Override
    public String getName() {
        return "login.Confirm";
    }
}
